<?php

namespace App\Service\Common;

use App\Enums\Common\AreaEnum;
use App\Enums\OpenShop\FeishuMini\ProgrammingEnum;
use App\Enums\OpenShop\InvestmentPromotion\SiteLocationEnum;
use App\Http\Middleware\OpenShop\WangGuiCityByPower;
use App\Models\Amap\AmapRegionBoundaryModel;
use App\Models\Common\ConfigModel;
use App\Models\Common\MapTownshipPlanAreaModel;
use App\Models\OpenShop\SiteLocation\OpenShopSiteLocationModel;
use App\Remote\Rms\RmsAreaRemote;
use App\Service\OpenShop\SiteLocation\GuanyuanDataService;
use App\Service\OpenShop\User\RmsUserService;
use App\Service\OpenShop\Wap\SignOrderService;
use App\Service\Rms\ShopService;
use Ballen\Distical\Calculator as DistanceCalculator;
use Ballen\Distical\Entities\LatLong;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use League\Geotools\Coordinate\Coordinate;
use League\Geotools\Polygon\Polygon;

class AreaService
{
    public static function getAreaCodeByArea($lng, $lat)
    {
        if (!$lng || !$lat) {
            return [];
        }

        $key     = WangGuiCityByPower::getRandomAmapKey();
        $areaRes = Http::withHeaders(['Content-Type' => 'application/json; charset=utf-8'])
            ->get(vsprintf(config('area.getReginDetailByLatLng'), [$lng, $lat, $key]))
            ->json();

        // $areaRes = Http::withHeaders(['Content-Type' => 'application/json; charset=utf-8'])
        //     ->get(sprintf(config('area.getAreaUrl'), $lat, $lng))
        //     ->json();
        if (($areaRes['status'] ?? -1) != 1) {
            return [
                'area'  => [],
                'grade' => (string)SiteLocationEnum::CITY_TYPE_LEVEL_5
            ];
        }


        //针对东莞的特殊算法
        $district = isset($areaRes['regeocode']['addressComponent']['district']) ? (is_array($areaRes['regeocode']['addressComponent']['district']) ? '' : $areaRes['regeocode']['addressComponent']['district']) : '';
        $province = isset($areaRes['regeocode']['addressComponent']['province']) ? (is_array($areaRes['regeocode']['addressComponent']['province']) ? '' : $areaRes['regeocode']['addressComponent']['province']) : '';
        $city     = isset($areaRes['regeocode']['addressComponent']['city']) ? (is_array($areaRes['regeocode']['addressComponent']['city']) ? '' : $areaRes['regeocode']['addressComponent']['city']) : '';
        $town     = isset($areaRes['regeocode']['addressComponent']['township']) ? (is_array($areaRes['regeocode']['addressComponent']['township']) ? '' : $areaRes['regeocode']['addressComponent']['township']) : '';

        if (!mb_strlen($city)) {
            $city     = $province;
        }
        if (!mb_strlen($district)) {
            if (!mb_strlen($city)) {
                $city     = $province;
                $district = $town;
            } else {
                $district = $city;
            }
        }

        $area = $province . '-' . $city . '-' . $district;

        $data = RmsUserService::getAreaCodeByArea($area);
        if (empty($data)) {
            return [];
        }
        $grade = SiteLocationEnum::CITY_TYPE_LEVEL_5;
        $res   = true;
        foreach ($data as $datum) {
            if ($datum['level'] == AreaEnum::LEVEL_PROVINCE) {
                //从RMS拿数据如果区域code为0 不自动匹配省市区  控制一级
                if ($datum['code'] == 0) {
                    $res = false;
                    break;
                }
                $province = [
                    'code' => $datum['code'],
                    'text' => $province,
                ];
            }
            if ($datum['level'] == AreaEnum::LEVEL_CITY) {
                $city  = [
                    'code' => $datum['code'],
                    'text' => $city,
                ];
                $grade = RmsAreaRemote::getCityGrade($datum['code']) ?: SiteLocationEnum::CITY_TYPE_LEVEL_5;
            }
            if ($datum['level'] == AreaEnum::LEVEL_DISTRICT) {
                $district = [
                    'code' => $datum['code'],
                    'text' => $district,
                ];
            }
        }
        $nearby             = GuanyuanDataService::closestShop($lat, $lng, (is_array($city) ? $city['text'] : $city));
        $nearby['distance'] = round($nearby['distance'], 2);
        $nearby['town']     = $town;

        if ($nearby['town'] != '-' && mb_strlen($nearby['town'])) {
            $nearby['townGrade']     = (int)MapTownshipPlanAreaModel::query()->where('area', $nearby['town'])->value('grade');
            $nearby['townGradeText'] = ProgrammingEnum::GRADE_MAPPING[$nearby['townGrade']] ?? '';
        }

        // 附近点位信息
        $minNearByPlaceholderInfo = [
            'nearbyPlaceHolderId'    => 0,
            'nearbyPlaceHolderRange' => 0,
            'nearbyPlaceHolderName'  => '该城市内无预占点位',
            'nearbyPlaceholderTime'  => ''
        ];
        $nearbyPlaceHolderName    = '';
        $placeholderList          = OpenShopSiteLocationModel::query()
            ->where(
                'source',
                OpenShopSiteLocationModel::SOURCE_PLACEHOLDER
            )
            ->where('placeholderTime', '>', time())
            ->where(function ($query) use ($city) {
                if (isset($city['code'])) {
                    $query->where('cityCode', $city['code']);
                }
            })
            ->where(
                'siteStatus',
                OpenShopSiteLocationModel::SITE_STATUS_4
            )
            ->get();
        //        dd($placeholderList);

        foreach ($placeholderList as $placeholder) {
            try {
                $distance = (new DistanceCalculator(
                    new LatLong($lat, $lng),
                    new LatLong($placeholder->latitude, $placeholder->longitude)
                ))->get()->asKilometres();
            } catch (\Exception $exception) {
                $distance = 0;
            }


            if ($minNearByPlaceholderInfo['nearbyPlaceHolderId'] == 0) {
                $minNearByPlaceholderInfo = [
                    'nearbyPlaceHolderId'      => $placeholder->id,
                    'nearbyPlaceHolderOrderNo' => $placeholder->orderNo,
                    'nearbyPlaceHolderRange'   => round($distance, 2),
                    'nearbyPlaceholderTime'    => date('Y-m-d H:i:s', $placeholder->placeholderTime),
                ];
            }

            if (bccomp($minNearByPlaceholderInfo['nearbyPlaceHolderRange'], $distance) == 1) {
                $minNearByPlaceholderInfo = [
                    'nearbyPlaceHolderId'      => $placeholder->id,
                    'nearbyPlaceHolderOrderNo' => $placeholder->orderNo,
                    'nearbyPlaceHolderRange'   => round($distance, 2),
                    'nearbyPlaceholderTime'    => date('Y-m-d H:i:s', $placeholder->placeholderTime),
                ];
            }

            if (!empty($minNearByPlaceholderInfo['nearbyPlaceHolderOrderNo'])) {
                $signOrderInfo                                     = (new SignOrderService($minNearByPlaceholderInfo['nearbyPlaceHolderOrderNo']))->getSignOrder();
                $nearbyPlaceHolderName                             = ShopService::getShopNameByCode($signOrderInfo->shopCode) ?? '';
                $minNearByPlaceholderInfo['nearbyPlaceHolderName'] = $nearbyPlaceHolderName ?: '该城市内无预占点位';

                unset($minNearByPlaceholderInfo['nearbyPlaceHolderOrderNo']);
            }
        }

        //        dd($minNearByPlaceholderInfo);

        if (!isset($grade['cityInfo']['grade']) || !$grade['cityInfo']['grade']) {
            $grade = (string)SiteLocationEnum::CITY_TYPE_LEVEL_5;
        } else {
            $grade = (string)$grade['cityInfo']['grade'];
        }
        return array_merge([
            'area'  => $res ? [$province ?? 0, $city ?? 0, $district ?? 0] : [],
            'grade' => $grade,
            'image' => "https://restapi.amap.com/v3/staticmap?location={$lng},{$lat}&markers=-1,https://file.51kuafu.com/e0/0c/cc0783d7de4fd65c070c14510370bf7dd73969cf2cf804cfe797d5dd23cd.png,0:{$lng},{$lat}&zoom=16&size=646*204&key=" . WangGuiCityByPower::getRandomAmapKey(),
        ], $nearby, $minNearByPlaceholderInfo);
    }

    public static function getCityGradeByCityCode($cityCode)
    {
        $grade = RmsAreaRemote::getCityGrade($cityCode);
        return [
            'grade' => (string)(($grade['cityInfo']['grade'] ?? SiteLocationEnum::CITY_TYPE_LEVEL_9) ?: SiteLocationEnum::CITY_TYPE_LEVEL_9)
        ];
    }


    /**
     * 通过经纬度获得省市区
     * 纯资源类型获取 不调用api
     * @param $lat
     * @param $lng
     * @param string $province 可选参数 增加查询性能
     * @return array
     */
    public static function getAdCodeByLatAndLng($lat, $lng, string $province = ''): array
    {
        // 获得省份下市code查询 增加效率
        $paramCode = Cache::remember('tiger:amap:cityCodeList', 3600, function () use ($province) {
            $city = AmapRegionBoundaryModel::query()
                ->where('level', AmapRegionBoundaryModel::LEVEL_PROVINCE)
                ->when(mb_strlen($province), function ($query) use ($province) {
                    if (is_numeric($province)) {
                        $query->where('code', $province);
                    } else {
                        $province = mb_substr($province, 0, 2);
                        $query->where('name', 'like', "{$province}%");
                    }
                })
                ->with(['cityTerritorialBoundaryRelByCity'])
                ->select(['code', 'pCode'])
                ->first();

            if (null == $city) {
                Cache::forget('tiger:amap:cityCodeList');
                return [];
            } else {
                return optional($city->cityTerritorialBoundaryRelByCity)->pluck('code')->toArray() ?: [];
            }
        });

        // 获得区域code
        $districtCode = 0;
        $cityCode     = 0;
        $districtName = '';
        AmapRegionBoundaryModel::query()
            ->when(!empty($paramCode), function ($query) use ($paramCode) {
                $query->whereIn('pCode', $paramCode);
            })
            ->where('level', AmapRegionBoundaryModel::LEVEL_DISTRICT)
            ->chunkById(20, function ($districtList) use ($lat, $lng, &$cityCode, &$districtCode, &$districtName) {
                foreach ($districtList as $district) {
                    $boundary = collect(json_decode($district->boundary, true))
                        ->map(function ($dot) {
                            if (!isset($dot[0]) || !isset($dot[1]) || $dot[0] == 0 || $dot[1] == 0) {
                                return null;
                            }
                            return [
                                (float)$dot[0],
                                (float)$dot[1]
                            ];
                        })->filter()->values()->toArray();
                    // 创建一个多边形
                    $polygon = new Polygon($boundary);
                    // 判断是否在多边形上
                    $res = $polygon->pointInPolygon(new Coordinate([$lng, $lat]));
                    if ($res) {
                        $cityCode     = $district->pCode;
                        $districtCode = $district->code;
                        $districtName = $district->name;
                        break;
                    }
                }
            });

        // 根据$districtCode获得省市区的code
        $cityModel     = AmapRegionBoundaryModel::query()->where('code', $cityCode)->select(['code', 'pCode', 'name'])->first();
        $provinceModel = AmapRegionBoundaryModel::query()->where('code', $cityModel->pCode)->select(['code', 'name'])->first();

        return [
            'provinceCode' => $provinceModel->code,
            'cityCode'     => $cityModel->code,
            'districtCode' => $districtCode,
            'provinceName' => $provinceModel->name,
            'cityName'     => $cityModel->name,
            'districtName' => $districtName,
        ];
    }


    /**
     * 根据adcode获得 华北 华南 等···
     * @param $adcode
     * @return int|string
     */
    public static function getRegionByChinaWithAdcode($adcode)
    {
        $arr = ConfigModel::getValueNewJson('siteLocation', 'locationAreaByChina');
        foreach ($arr as $region => $item) {
            if (in_array($adcode, $item)) {
                return $region;
            }
        }
        return '';
    }


    /**
     * 根据省市区汉子匹配code
     * @param $province
     * @param $city
     * @param $district
     * @return array|array[]
     */
    public static function getAdcodeByProvinceCityDistrict($province, $city, $district): array
    {
        $default = [
            'province' => [
                'name' => $province,
                'code' => 0,
            ],
            'city'     => [
                'name' => $city,
                'code' => 0,
            ],
            'district' => [
                'name' => $district,
                'code' => 0,
            ],
        ];


        $provinceModel = AmapRegionBoundaryModel::query()
            ->where('level', AmapRegionBoundaryModel::LEVEL_PROVINCE)
            ->where('name', 'like', mb_substr($province, 0, 2) . '%')
            ->select(['name', 'code'])
            ->first();

        if (null != $provinceModel) {
            $provinceInfo = $provinceModel->toArray();
        } else {
            return $default;
        }

        if ($provinceInfo['code'] == 0) {
            return $default;
        }

        $special = false;

        // 重庆特殊处理
        if (mb_substr($province, 0, 2) == '重庆') {
            $special = true;
        }

        $cityModel = AmapRegionBoundaryModel::query()
            ->where('pCode', $provinceInfo['code'])
            ->where('level', AmapRegionBoundaryModel::LEVEL_CITY)
            ->where('name', 'like', mb_substr($city, 0, 2) . '%')
            ->select(['name', 'code'])
            ->first();

        if (null != $cityModel) {
            $cityInfo         = $cityModel->toArray();
            $cityInfo['name'] = str_replace('城区', '市', $cityInfo['name']);
            if ($special) {
                $cityInfo['name'] = str_replace('郊县', '市', $cityInfo['name']);
            }
        } else {
            return $default;
        }

        if ($cityInfo['code'] == 0) {
            return $default;
        }

        if ($city == $district) {
            return [
                'province' => $provinceInfo,
                'city'     => $cityInfo,
                'district' => $cityInfo,
            ];
        }

        if (in_array(mb_substr($city, 0, 2), ['东莞', '中山', '儋州', '济源', '潜江', '嘉峪'])) {
            return [
                'province' => $provinceInfo,
                'city'     => $cityInfo,
                'district' => $cityInfo,
            ];
//            $districtLevelArr = [AmapRegionBoundaryModel::LEVEL_DISTRICT, AmapRegionBoundaryModel::LEVEL_STREET];
        } else {
            $districtLevelArr = [AmapRegionBoundaryModel::LEVEL_DISTRICT];
        }

        $districtModel = AmapRegionBoundaryModel::query()
            ->when($special, function ($query) {
                $query->whereIn('pCode', [500100, 500200]);
            })
            ->when(!$special, function ($query) use ($cityInfo) {
                $query->where('pCode', $cityInfo['code']);
            })
            ->whereIn('level', $districtLevelArr)
            ->where('name', $district)
            ->select(['name', 'code', 'pCode'])
            ->first();

        if (null != $districtModel) {
            $districtInfo = $districtModel->toArray();
        } else {
            return $default;
        }

        if ($districtInfo['code'] == 0) {
            return $default;
        }

        if ($special) {
            $cityInfo['code'] = $districtModel['pCode'];
        }

        unset($districtInfo['pCode']);

        return [
            'province' => $provinceInfo,
            'city'     => $cityInfo,
            'district' => $districtInfo,
        ];

    }


}
